home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************************
- *
- *
- * SimpleHelp.c -implementation of simplehelp system
- *
- * ©1994, Graham Cox. All Rights Reserved.
- *
- * 9/2/94
- * 28/6/94 First List Item now Hilited on startup of help
- * Hypertext links now track mouse like buttons
- * Links flash on mouse up like menus
- * SetHyperlinkMatchStyle now correctly sets up data internally
- * Buttons now correctly hilited at startup of help
- * Now handles up and down arrow keys to select topics
- * 29/6/94 Manages resource file correctly for when help is a seperate file
- * 14/7/94 Reworked to compile under CodeWarrior for the PowerPC
- *
- ****************************************************************************************/
-
- #include "SimpleHelpTypes.h"
- #include "ColourPopUp.h"
- #include <Errors.h>
-
- #define SetHiliteMode() LMSetHiliteMode(LMGetHiliteMode() &! hiliteBit)
-
- Handle GetUniversalFunctionHandle(ProcPtr functionAddress,ProcInfoType pInfo);
-
-
- ListHandle gTopicList = NIL;
-
- void DrawHelpTopicCell(Cell tCell,short dataLen,ListHandle theList,Rect *dCell);
-
- #define helpTopicTitle 7
-
- OSErr BuildTopicList(SimHelpHdl sHelp,Rect *listBox)
- {
- /* this function builds the topic list. It first creates the list manager record and
- installs the custom draw proc. It then opens the resource which defines the topic
- list, and reads in each entry, storing it in the list. The sHelp record (which
- must already have been created and otherwise initialised) has the list handle
- stored into it. */
-
- ListHandle theList;
- topicListHdl topicList;
- topicRecPtr topicEntry;
- Rect dataBounds;
- Point cSize;
- short index;
- Cell curCell;
- short recSize;
- OSErr btErr = memFullErr;
- Handle funcLDEF;
-
- if (sHelp != NIL)
- {
- topicList = (topicListHdl) GetResource(topicListResType,(*sHelp)->topicID);
-
- btErr = ResError();
-
- if (topicList != NIL)
- {
- HNoPurge((Handle) topicList);
-
- SetRect(&dataBounds,0,0,1,(*topicList)->nTopics + 1);
- SetPt(&cSize,0,0);
- listBox->right -= 15; // allow for scrollbar
- InsetRect(listBox,1,1); // and frame
-
- theList = LNew(listBox,&dataBounds,cSize,0,(*sHelp)->ownerWindow,
- FALSE,FALSE,FALSE,TRUE);
-
- InsetRect(listBox,-1,-1);
- listBox->right += 15;
-
- if (theList != NIL)
- {
- MoveHHi((Handle) topicList);
- HLock((Handle) topicList);
- topicEntry = &(*topicList)->theTopic;
- curCell.v = 0;
- curCell.h = 0;
-
- for(index = 0;index <= (*topicList)->nTopics;index++)
- {
- recSize = sizeof(topicRec) + topicEntry->topicString - 1;
-
- LSetCell((Ptr) topicEntry,recSize,curCell,theList);
-
- topicEntry = (topicRecPtr)((long)topicEntry + recSize);
- // point at next record (variable size)
- curCell.v++;
- }
- HUnlock((Handle) topicList);
-
- (*sHelp)->topicList = theList; // set record field
-
- funcLDEF = GetUniversalFunctionHandle((ProcPtr)TopicListDef,uppListDefProcInfo);
- (*theList)->listDefProc = funcLDEF;
- (*theList)->userHandle = (Handle) sHelp;
- }
- HPurge((Handle) topicList);
- ReleaseResource((Handle) topicList);
- }
- }
- return(btErr);
- }
-
-
- SimHelpHdl GetNewHelpDialog(short DialogID,short listItem,short textItem,short topicID)
- {
- /* highish level call to get the dialog and build its internal data structures. These
- include the scrolling text panel and the topic list */
-
- SimHelpHdl sHelp = NIL;
- DialogPtr helpDialog;
- OSErr btErr;
- Rect rViewRect;
- short itemType;
- Handle itemHand;
- GrafPtr savePort;
- Cell firstCell = {0,0};
- static UserItemUPP gMyUserItemUPP;
-
- helpDialog = GetTextDialog(DialogID,textItem,defaultTextResID,FALSE);
-
- if (helpDialog != NIL)
- {
- sHelp = (SimHelpHdl) NewHandleClear(sizeof(SimHelpRecord));
-
- if (sHelp != NIL)
- {
- (*sHelp)->ownerWindow = helpDialog;
- (*sHelp)->topicID = topicID;
- (*sHelp)->indentPixels = defaultIndent;
- (*sHelp)->listItemID = listItem;
- (*sHelp)->textItemID = textItem;
- (*sHelp)->helpResFileRef = -1;
- (*sHelp)->swapResFileRef = -1;
-
- GetPort(&savePort);
- SetPort(helpDialog);
- TextFont(defaultFont);
- TextSize(defaultFontSize);
-
- (*sHelp)->missingPageID = pageMissingStrID;
- (*sHelp)->fontID = defaultFont;
- (*sHelp)->fontSize = defaultFontSize;
-
- (*sHelp)->hyperTextStyle = bold; // default style for hypertext
- (*sHelp)->hyperTextIndex = -1; // index not initialised
-
- GetDItem(helpDialog,listItem,&itemType,&itemHand,&rViewRect);
- if ((itemType & 0x7F) == userItem)
- {
- btErr = BuildTopicList(sHelp,&rViewRect);
-
- gTopicList = (*sHelp)->topicList; // annoyingly necessary...
-
- gMyUserItemUPP = NewUserItemProc((ProcPtr) ListDrawProc);
- itemHand = (Handle) gMyUserItemUPP;
- SetDItem(helpDialog,listItem,itemType,itemHand,&rViewRect);
- }
- LDoDraw(TRUE,gTopicList);
- LActivate(TRUE,gTopicList);
- LSetSelect(TRUE,firstCell,(*sHelp)->topicList);
-
- TextFont(0);
- TextSize(12);
-
- SwitchPage(sHelp,(*sHelp)->lastSelection);
- itemType = helpPrevButton;
- HandleHelpItems(sHelp,&itemType);
-
- SetPort(savePort);
- }
- }
-
- return(sHelp);
- }
-
-
- void DisposeHelpDialog(SimHelpHdl sHelp)
- {
- /* disposes of everything, including dialog box itself */
-
- Handle defProc;
-
- if (sHelp != NIL)
- {
- defProc = (*(*sHelp)->topicList)->listDefProc;
- LDispose((*sHelp)->topicList);
- gTopicList = NIL;
- DisposHandle(defProc);
- DisposeTDDialog((*sHelp)->ownerWindow);
- DisposHandle((Handle) sHelp);
- }
- }
-
-
- void SetHyperlinkMatchStyle(SimHelpHdl sHelp,short theStyle)
- {
- short hypIndex;
- TEHandle teRec;
-
- if (sHelp != NIL)
- {
- (*sHelp)->hyperTextStyle = theStyle;
- teRec = GetTDTextHdl((*sHelp)->ownerWindow);
- hypIndex = GetHypertextStyleRef(teRec,theStyle);
- (*sHelp)->hyperTextIndex = hypIndex;
- }
- }
-
-
- DialogPtr GetHelpDialogHdl(SimHelpHdl sHelp)
- {
- /* returns the dialog field */
-
- if (sHelp != NIL)
- return((*sHelp)->ownerWindow);
- else
- return(NIL);
- }
-
-
- void ModalHelpDialog(SimHelpHdl sHelp,short *theItem)
- {
- /* call replacement for ModalDialog. Handles list and text clicks, etc */
-
- while (*theItem == 0)
- {
- ModalTDDialog((short*)theItem);
- HandleHelpItems(sHelp,theItem);
- }
- }
-
-
- Boolean HandleHelpItems(SimHelpHdl sHelp,short *theItem)
- {
- Point mClick;
- GrafPtr savePort;
- Cell lastOne,thisOne;
- short itemType;
- Handle itemHand;
- Rect itemBox;
- Boolean retCode = FALSE;
-
- thisOne = lastOne = (*sHelp)->lastSelection;
-
- if (*theItem == (*sHelp)->listItemID)
- {
- *theItem = 0;
-
- /* handle list clicks */
- GetPort(&savePort);
- SetPort((*sHelp)->ownerWindow);
- GetMouse(&mClick);
-
- LClick(mClick,0,(*sHelp)->topicList);
- SetPt(&thisOne,0,0);
- if (LGetSelect(TRUE,&thisOne,(*sHelp)->topicList))
- {
- if (!EqualPt(thisOne,lastOne))
- {
- SwitchPage(sHelp,thisOne);
- (*sHelp)->lastSelection = thisOne;
- }
- }
- SetPort(savePort);
- retCode = TRUE;
- }
- else
- {
- switch (*theItem)
- {
- case helpNextButton:
- thisOne.v++;
- if (thisOne.v >= (*(*sHelp)->topicList)->dataBounds.bottom)
- thisOne.v = (*(*sHelp)->topicList)->dataBounds.bottom -1;
- else
- {
- LSetSelect(FALSE,lastOne,(*sHelp)->topicList);
- LSetSelect(TRUE,thisOne,(*sHelp)->topicList);
- LAutoScroll((*sHelp)->topicList);
- (*sHelp)->lastSelection = thisOne;
- SwitchPage(sHelp,thisOne);
- }
- *theItem = 0;
- retCode = TRUE;
- break;
- case helpPrevButton:
- thisOne.v--;
- if (thisOne.v < 0)
- thisOne.v = 0;
- else
- {
- LSetSelect(FALSE,lastOne,(*sHelp)->topicList);
- LSetSelect(TRUE,thisOne,(*sHelp)->topicList);
- LAutoScroll((*sHelp)->topicList);
- (*sHelp)->lastSelection = thisOne;
- SwitchPage(sHelp,thisOne);
- }
- *theItem = 0;
- retCode = TRUE;
- break;
- }
- }
- if (thisOne.v == (*(*sHelp)->topicList)->dataBounds.bottom -1)
- {
- GetDItem((*sHelp)->ownerWindow,
- helpNextButton,&itemType,&itemHand,&itemBox);
- HiliteControl((ControlHandle)itemHand,255);
- }
- if (thisOne.v != 0)
- {
- GetDItem((*sHelp)->ownerWindow,
- helpPrevButton,&itemType,&itemHand,&itemBox);
- HiliteControl((ControlHandle) itemHand,0);
- }
- if (thisOne.v == 0)
- {
- GetDItem((*sHelp)->ownerWindow,
- helpPrevButton,&itemType,&itemHand,&itemBox);
- HiliteControl((ControlHandle)itemHand,255);
- }
- if (thisOne.v != (*(*sHelp)->topicList)->dataBounds.bottom -1)
- {
- GetDItem((*sHelp)->ownerWindow,
- helpNextButton,&itemType,&itemHand,&itemBox);
- HiliteControl((ControlHandle) itemHand,0);
- }
- return(retCode);
- }
-
-
-
- pascal void ListDrawProc(WindowPtr theWindow,short theItem)
- {
- /* user item draw proc for the list. a TAD tricky because we haven't got the list
- handle- the refcon field is already in use by the scroll panel... */
-
- short itemType;
- Handle itemHand;
- Rect itemBox;
- RGBColor saveBack;
-
- GetDItem(theWindow,theItem,&itemType,&itemHand,&itemBox);
-
- if (gTopicList != NIL)
- LUpdate(qd.thePort->visRgn,gTopicList);
-
- Frame3DRect(&itemBox,FALSE); // Godrilla Mincefriend
- FrameRect(&itemBox);
- }
-
-
- void SwitchPage(SimHelpHdl sHelp,Cell clickCell)
- {
- /* looks up the text page for the given cell and installs that page */
-
- ListHandle theList;
- short dLen;
- bigTopicRec btRec;
-
- if (sHelp != NIL)
- {
- theList = (*sHelp)->topicList;
-
- dLen = sizeof(bigTopicRec);
- LGetCell(&btRec,&dLen,clickCell,theList);
- InstallPage(sHelp,btRec.pageID);
- ParamText(btRec.topicString,NIL,NIL,NIL);
- }
- }
-
-
- void InstallPage(SimHelpHdl sHelp,short pageID)
- {
- Handle theText;
- StringHandle errStr;
- TEHandle teRec;
- short hypIndex;
-
- if (sHelp != NIL)
- {
- if (pageID != 0)
- {
- SwapHelpResFile(sHelp,kSwapHelpIn);
-
- theText = GetResource('TEXT',pageID); // preflight check
- if (theText == NIL)
- {
- errStr = GetString((*sHelp)->missingPageID);
- TDSetText((*sHelp)->ownerWindow,((Ptr)*errStr) +1,*errStr[0],NIL);
- (*sHelp)->curPageResID = 0;
- }
- else
- {
- TDSetResourceText((*sHelp)->ownerWindow,pageID);
- (*sHelp)->curPageResID = pageID;
- }
-
- teRec = GetTDTextHdl((*sHelp)->ownerWindow);
- hypIndex = GetHypertextStyleRef(teRec,(*sHelp)->hyperTextStyle);
- (*sHelp)->hyperTextIndex = hypIndex;
-
- SwapHelpResFile(sHelp,kSwapHelpOut);
- }
- else
- {
- TDSetText((*sHelp)->ownerWindow,(Ptr)*errStr,0,NIL);
- (*sHelp)->curPageResID = 0;
- }
- }
- }
-
-
- pascal Boolean ModelessHelp(SimHelpHdl sHelp,short theItem,EventRecord *theEvent)
- {
- /* handles a modeless help window. Call after DialogSelect if it returns TRUE. */
-
- Boolean mtResult;
- short htLink;
- char keyHit;
-
- if (sHelp != NIL)
- {
- mtResult = ModelessText((*sHelp)->ownerWindow,theItem,theEvent);
-
- if (! mtResult)
- {
- switch(theEvent->what)
- {
- case mouseDown:
- if (! HandleHelpItems(sHelp,&theItem))
- {
- htLink = ResolveHypertextLink(sHelp,theEvent->where);
-
- if (htLink != -1)
- {
- /* we clicked a hypertext link. Unhilite the pick list and switch to
- the page resolved */
-
- LSetSelect(FALSE,(*sHelp)->lastSelection,(*sHelp)->topicList);
- (*sHelp)->lastSelection.v = -1;
- InstallPage(sHelp,htLink);
- }
- return(FALSE);
- }
- else
- return(TRUE);
- break;
- case keyDown:
- case autoKey:
- keyHit = theEvent->message & charCodeMask;
- switch (keyHit)
- {
- case 0x1F: //down arrow
- theItem = helpNextButton;
- HandleHelpItems(sHelp,&theItem);
- break;
- case 0x1E: // up arrow
- theItem = helpPrevButton;
- HandleHelpItems(sHelp,&theItem);
- break;
- }
- return(TRUE);
- break;
- }
- }
- }
- else
- return(FALSE);
- }
-
-
- /*--------------------------------------------------------------------------------------*/
-
- pascal void TopicListDef(short lMsg,Boolean lSelect,Rect *lRect,Cell lCell,
- short lDataOffset,short lDataLength,ListHandle theList)
- {
- /* this is the list definition function for th topic list. It is embedded in this code
- and will be called by the list manager using a 'sneaky jump'. */
-
- switch (lMsg)
- {
- case lInitMsg:
- break;
- case lDrawMsg:
- DrawHelpTopicCell(lCell,lDataLength,theList,lRect);
- if (!lSelect)
- break;
- case lHiliteMsg:
- SetHiliteMode();
- InvertRect(lRect);
- break;
- case lCloseMsg:
- break;
- }
- }
-
-
- void DrawHelpTopicCell(Cell tCell,short dataLen,ListHandle theList,Rect *dCell)
- {
- short tLen;
- bigTopicRecPtr tData;
- bigTopicRec tRec;
- FontInfo fInfo;
- SimHelpHdl sHelp;
- short indentPix,saveFont,saveSize;
-
- sHelp = (SimHelpHdl)(*theList)->userHandle; // might be handy...
-
- tLen = dataLen;
- tData = &tRec;
- LGetCell((Ptr) tData,&tLen,tCell,theList);
-
- saveFont = qd.thePort->txFont;
- saveSize = qd.thePort->txSize;
-
- TextFont(geneva);
- TextSize(9);
- GetFontInfo(&fInfo);
-
- indentPix = tRec.indent * (*sHelp)->indentPixels;
- MoveTo(dCell->left + indentPix + 1,dCell->top + fInfo.ascent - 1);
-
- TextFace(tRec.tStyle);
- DrawText(&tData->topicString,1,tData->topicString[0]);
-
- TextFace(0);
- TextFont(saveFont);
- TextSize(saveSize);
- }
-
-
- short GetHypertextStyleRef(TEHandle teRec,short theStyle)
- {
- /* returns an index value which represents the index in the StyleRun table of the
- entry which matches the given style. You need this to look up a hypertext link.
- Call after installing a new page. */
-
- TEStyleHandle teStyles;
- short i;
- STHandle styleTab;
- STElement styleEntry;
-
- if (teRec != NIL)
- {
- teStyles = GetStylHandle(teRec);
-
- if (teStyles != NIL)
- {
- styleTab = (*teStyles)->styleTab;
-
- for (i = 0; i < (*teStyles)->nStyles; i++)
- {
- styleEntry = (*styleTab)[i];
-
- if (styleEntry.stFace == theStyle)
- return(i);
- }
- }
- }
- return(-1);
- }
-
-
- short ResolveHypertextLink(SimHelpHdl sHelp,Point clickPt)
- {
- /* call after clicking in the text pane. This function resolves whether a hypertext
- link was clicked, handling all of the necessary feedback, such as highlighting,
- etc. It returns the page ID of the link, or -1 if not a link or page missing */
-
- TEHandle teRec;
- short charOffset,index,hypTextLen,pageRef = -1,i;
- GrafPtr savePort;
- TEStyleHandle teStyles;
- StyleRun stRun,nextRun;
- long ignored;
- Ptr textStart;
- Str255 hyperString;
- htIndexHdl hypIndex;
- Rect wordRect;
- Boolean trackPointIn,wasIn;
-
- if (sHelp != NIL && (*sHelp)->hyperTextIndex != -1)
- {
- teRec = GetTDTextHdl((*sHelp)->ownerWindow);
- if (teRec != NIL)
- {
- teStyles = GetStylHandle(teRec);
-
- if (teStyles != NIL)
- {
- GetPort(&savePort);
- SetPort((*sHelp)->ownerWindow);
- GlobalToLocal(&clickPt);
-
- charOffset = TEGetOffset(clickPt,teRec);
-
- if (charOffset > 0 && charOffset < (*teRec)->teLength)
- {
- // scan the runs array for the style of the clicked char
-
- for (index = 0;index < (*teStyles)->nRuns;index++)
- {
- stRun = (*teStyles)->runs[index];
- nextRun = (*teStyles)->runs[index +1];
-
- if (charOffset >= stRun.startChar && charOffset < nextRun.startChar)
- {
- /* we found the char. Does the hypertext index match? */
-
- if (stRun.styleIndex == (*sHelp)->hyperTextIndex)
- {
- /* yes- fetch the string and hilite it */
-
- TESetSelect(stRun.startChar,nextRun.startChar,teRec);
- TEActivate(teRec);
-
- wordRect = (*teRec)->selRect;
- /* track the rect as long as the mouse is down */
-
- trackPointIn = wasIn = TRUE;
-
- while (WaitMouseUp())
- {
- GetMouse(&clickPt);
- trackPointIn = PtInRect(clickPt,&wordRect);
- if (trackPointIn &! wasIn)
- TEActivate(teRec);
- else
- if (wasIn &! trackPointIn)
- TEDeactivate(teRec);
- wasIn = trackPointIn;
- }
- if (wasIn)
- {
- for(i = 0;i < 3;i++)
- {
- TEDeactivate(teRec);
- Delay(5,&ignored);
- TEActivate(teRec);
- Delay(5,&ignored);
- }
- TEDeactivate(teRec);
- hypTextLen = nextRun.startChar - stRun.startChar;
- textStart = (Ptr)(*(*teRec)->hText + stRun.startChar);
- BlockMove(textStart,&hyperString[1],hypTextLen);
- hyperString[0] = hypTextLen;
-
- /* now search the hypertext index for this page to match
- this string */
-
- hypIndex = (htIndexHdl) GetResource(hyperTextIndexType,
- (*sHelp)->curPageResID);
- if (hypIndex != NIL)
- {
- pageRef = MatchHyperLink(&hyperString,hypIndex);
- HPurge((Handle) hypIndex);
- ReleaseResource((Handle) hypIndex);
- }
- }
- break; // jump out of the loop
- }
- }
- }
- }
- SetPort(savePort);
- }
- }
- }
- return(pageRef);
- }
-
-
- short MatchHyperLink(Str255 *testStr,htIndexHdl pageIndex)
- {
- /* searches the page index record for a match with the test string. When found, the
- corresponding page ID is returned, otherwise, -1 is returned */
-
- Ptr recStart;
- long recSize;
- short recCount,index;
- hypEntry curEntry;
-
- if (pageIndex != NIL)
- {
- HNoPurge((Handle) pageIndex);
-
- recCount = (*pageIndex)->nEntries;
- MoveHHi((Handle) pageIndex);
- HLock((Handle) pageIndex);
-
- recStart = (Ptr) &(*pageIndex)->hEntries[0];
-
- for (index = 0;index < recCount;index++)
- {
- recSize = sizeof(hypEntry);
- BlockMove(recStart,&curEntry,recSize);
-
- if (EqualString(*testStr,curEntry.htMatchString,FALSE,FALSE))
- {
- HUnlock((Handle) pageIndex);
- return(curEntry.pageID);
- }
- recSize = curEntry.htMatchString[0] + sizeof(short) + 1;
- recStart += recSize;
- }
- HUnlock((Handle) pageIndex);
- }
- return(-1);
- }
-
-
- void SetHelpResFile(SimHelpHdl sHelp,short refNum)
- {
- /* sets the help file resource refnum */
-
- (*sHelp)->helpResFileRef = refNum;
- }
-
-
- void SwapHelpResFile(SimHelpHdl sHelp,Boolean hSwapContext)
- {
- /* switches the resource files according to the flag */
-
- if (hSwapContext == kSwapHelpIn)
- {
- (*sHelp)->swapResFileRef = CurResFile();
- if ((*sHelp)->helpResFileRef != -1)
- UseResFile((*sHelp)->helpResFileRef);
- }
- else
- {
- if ((*sHelp)->swapResFileRef != -1)
- UseResFile((*sHelp)->swapResFileRef);
- }
- }
-